#include "DnsServerConfiguration.h"
#include "commandLineParser.h"
#include "helper.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cctype>

DnsServerConfiguration::DnsServerConfiguration( int argc, char *argv[] )
{
	setDefaults();
	std::string file = parser( argc, argv, "--config" );
	if( file.size() == 0 ) 
	{
		file = parser( argc, argv, "-c" );
	}
	if( file.size() > 0 )
		configFile_ = file;

	std::string verbose = parser( argc, argv, "--verbose" );
	if( verbose.size() == 0 )
	{
		verbose = parser( argc, argv, "-v" );
	}
	if( verbose.size() > 0 )
		verbose_ = true;

	std::string help = parser( argc, argv, "--help" );
	if( help.size() == 0 )
	{
		help = parser( argc, argv, "-h" );
	}
	if( help.size() > 0 )
	{
		printHelp();
		exit( 0 );
	}
	
	readConfigFile();
	parseCommandLine( argc, argv );
}

DnsServerConfiguration::~DnsServerConfiguration()
{

}

void DnsServerConfiguration::setDefaults()
{
	configFile_ = DEFAULT_CONFIG_LOCATION;
	verbose_ = false;
	listenPort_ = 53;
	listenAddress_ = "127.0.0.1";
	forwarder_ = false;
	purePassiveMode_ = false;

	//INTEL FEATURES
	detectFastFlux_ = true;
	fastFluxChangesPerPeriod_ = 5; 
	fastFluxChangesPerPeriod_ = 3600; //1 hr
	logViolations_ = true;
	violationLog_ = DEFAULT_VIOLATION_LOG;
	 
	//Security Features
	Ox20Encoding_ = true;
	randomizeIDs_ = true;
	randomizeSourcePorts_ = true; 
	dropCachePoisonedEntries_ = true;
	relookupCachePoisonedEntries_ = true;
	identifyCachePoisoningPassively_ = false;

}

void DnsServerConfiguration::readConfigFile()
{
	verbose( "Reading " + configFile_ + ": "  );
	std::vector< std::string > file;
	std::string line;
	

  std::ifstream infile;
	infile.open( configFile_.c_str() );
	while( getline( infile, line ) )
	{
		sanitizeConfigLine( line );
		if( line.size() > 0 )
			file.push_back( line );
	}

  //Parse out the config options
  for( uint32_t i = 0; i < file.size(); ++i )
	{
		std::vector< std::string > option = split( file[i], '=' );

		if( option.size() != 2 )
		{
			std::cerr << "Error with parsing the options on line: " << file[i] << std::endl;
			exit( 1 );
		}
		trim( option[0] );
		trim( option[1] );

		std::transform( option[0].begin(), option[0].end(), option[0].begin(), tolower);

		//std::cout << option[0] << std::endl;
		//std::cout << option[1] << std::endl;

		if( option[0] == "listenaddress" )
		{
			verbose( "\tSetting ListenAddress to " + option[1] );
			listenAddress_ = option[1];
		}
		else if( option[0] == "listenport" )
		{
			verbose( "\tSetting ListenPort to " + option[1] );
			listenPort_ = ss_atoi<uint16_t>( option[1] );
		}
		else if( option[0] == "forwarders" )
		{
			verbose( "\tSetting forwarder on..." );
			forwarder_ = true;
			forwarders_ = split( option[1], ',' );
			for( uint32_t i = 0; i < forwarders_.size(); ++i )
			{
				trim(forwarders_[i]);
				verbose( "\t\tForwarder Added " + forwarders_[i] );
			}
		}
		else if( option[0] == "detectfastflux" )
		{
			std::transform( option[1].begin(), option[1].end(), option[1].begin(), tolower);
			if( option[1] == "true" )
				detectFastFlux_ = true;
			else if ( option[1] == "false" )
				detectFastFlux_ = false;
			else
			{
				verbose( "Bad Option - DetectFastFlux = " + option[1] );
				detectFastFlux_ = false;
			}
			verbose( "\tSetting DetectFastFlux to " + static_cast<std::string>(detectFastFlux_ ? "true" : "false") );
		}
		else if( option[0] == "fastfluxchangesperperiod" )
		{
			verbose( "\tSetting FastFluxChangesPerPeriod to " + option[1] );
			fastFluxChangesPerPeriod_ = ss_atoi<int>( option[1]);
		}
		else if( option[0] == "fastfluxperiod" )
		{
			verbose( "\tSetting FastFluxPeriod to " + option[1] );
			fastFluxPeriod_ = ss_atoi<int>( option[1] );
		}
		else
		{
			verbose( "\tUnrecognized Option: " + option[0] + " = " + option[1] );
		}
	}


}

std::vector<std::string> & DnsServerConfiguration::split(const std::string &s, char delim, std::vector<std::string> &elems) 
{
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}


std::vector<std::string> DnsServerConfiguration::split(const std::string &s, char delim) 
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}
void DnsServerConfiguration::sanitizeConfigLine( std::string &line )
{
	//remove comments
	std::string::size_type foundAt;
	foundAt = line.find( "#" );
	if( foundAt != std::string::npos )
	{
		//there was a comment
		line = line.substr( 0, foundAt ); 
	}
  trim( line );
}

void DnsServerConfiguration::trim( std::string& str )
{
	// Trim Both leading and trailing spaces
	size_t startpos = str.find_first_not_of(" \t"); // Find the first character position after excluding leading blank spaces
	size_t endpos = str.find_last_not_of(" \t"); // Find the first character position from reverse af

	// if all spaces or empty return an empty string
	if(( std::string::npos == startpos ) || ( std::string::npos == endpos))
	{
		str = "";
	}
	else
		str = str.substr( startpos, endpos-startpos+1 );

	/*
	// Code for  Trim Leading Spaces only
	size_t startpos = str.find_first_not_of(” \t”); // Find the first character position after excluding leading blank spaces
	if( string::npos != startpos )
	str = str.substr( startpos );
	 */

	/*
	// Code for Trim trailing Spaces only
	size_t endpos = str.find_last_not_of(” \t”); // Find the first character position from reverse af
	if( string::npos != endpos )
	str = str.substr( 0, endpos+1 );
	 */
}

void DnsServerConfiguration::parseCommandLine( int argc, char *argv[] )
{

}

void DnsServerConfiguration::printHelp()
{

	std::cout << "DNS Server v0.1a" << std::endl;
	std::cout << "\tCopyright 2010" << std::endl;
	std::cout << std::endl;
	std::cout << "Options: " << std::endl;
	std::cout << "\t--config or -c <config file>" << std::endl;
	std::cout << "\t--verbose or -v" << std::endl;
	std::cout << "\t--help or -h " << std::endl;

}

void DnsServerConfiguration::verbose( const std::string & message )
{
	if( verbose_ )
	{
		MutexLocker lock( verboseMutex_ );
		std::cerr << message << std::endl;
	}
}

std::string DnsServerConfiguration::listenAddress() const
{
	return listenAddress_;
}

uint16_t DnsServerConfiguration::listenPort() const
{
	return listenPort_;
}

std::vector< std::string > DnsServerConfiguration::forwarders() const
{
	return forwarders_;
}

bool DnsServerConfiguration::forward() const
{
	return forwarder_;
}

